<?php

namespace app\batch;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use app\models\{User as Users, Money, Moneylog, Price, Config, Order, Orderlog, Quotes};
use think\Facade\Config as Configs;
use think\Db;
use app\facade\Redis;
use think\facade\Debug;


class MatchOrder extends Command
{
    private $url = 'https://api-aws.huobi.pro/';
    protected function configure()
    {
        $this->setName('MatchOrder')->setDescription('订单匹配');
    }

    protected function execute(Input $input, Output $output)
    {
        $this->doCron();
        die();
    }

    protected function doCron()
    {
        $cmd = "ps aux | grep '/www/server/php/72/bin/php /www/wwwroot/JTE/think MatchOrder'|grep -v 'grep'| awk '{print $2}'";
        exec($cmd, $ps, $ret);
        if (count($ps) > 1) {
            die("batch of  is running");
        }
        ini_set('max_execution_time', 0);
        $dataconfig = [];
        //查找卖单进行买单匹配
        $list = (new Order())->where(['status' => 1, 'type' => 2])->select();
        $rdstime = 2;
        foreach ($list as $lists) {

            //限价匹配
            $rdslistsid = 'MatchOrder' . $lists['id'];
            $rdslist = Redis::get($rdslistsid);
            if (!$rdslist) {
                $orders = (new Order())->where(['coin' => $lists['coin'], 'mart' => $lists['mart'], 'status' => 1, 'type' => 1])->order(['commprice' => 'desc', 'created' => 'asc'])->find();
                //匹配对查询
                if (empty($orders)) {
                    echo '跳过1';
                    continue;
                }

                if ($lists['user_id'] == 0 && $orders['user_id'] == 0) {
                    echo '跳过...';
                    continue;
                }
                $configs = (new Quotes())->where(['coin' => $orders['coin'], 'mart' => $orders['mart']])->field('buyhand,sellhand,blurry')->find();
                Redis::setex($rdslistsid, $rdstime, $lists['id']);
                if ($lists['prmoney'] == 1) {
                    if ($orders['prmoney'] == 1) {
                        //限价对限价 价格相等或买单价格高于卖单价格时匹配
                        if ($orders['commprice'] >= $lists['commprice']) {
                            $rdslistsid = 'MatchOrder' . $orders['id'];
                            //进行匹配
                            if (!Redis::get($rdslistsid)) {
                                Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                Db::startTrans();
                                try {
                                    $this->matchOrders($orders, $lists, $orders['commprice'], $configs);
                                    Db::commit();
                                } catch (\Exception $e) {
                                    dump($e->getMessage());
                                    Db::rollback();
                                }
                            }
                        }
                    } else {
                        //计算买单限价对卖单市价的价格
                        $coin = Configs::get('config.coins.' . $lists['coin']);
                        $mart = Configs::get('config.coins.' . $lists['mart']);
                        if ($lists['coin'] == 1) {
                            if ($mart == 'USDT') {
                                $price = (new Orderlog())->where(['coins' => $orders['coin'], 'mart' => $orders['mart']])->order('id desc')->value('price');
                                if ($price == 0) {
                                    $price = (new Price())->where('dates', '<=', date('Y-m-d'))->where(['coin' => $orders['coin'], 'mart' =>  $orders['mart'], 'istrue' => 1])->order('dates desc')->value('price') ?? 0;
                                }
                                $minprice = (100 - $configs['blurry']) * $price / 100;
                                $maxprice = (100 + $configs['blurry']) * $price / 100;
                                if (!empty($price) && $price > 0 && $lists['commprice'] >= $minprice && $lists['commprice'] <= $maxprice) {
                                    $rdslistsid = 'MatchOrder' . $orders['id'];
                                    //进行匹配
                                    if (!Redis::get($rdslistsid)) {
                                        Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                        Db::startTrans();
                                        try {
                                            $this->matchOrders($orders, $lists, $lists['commprice'], $configs);
                                            Db::commit();
                                        } catch (\Exception $e) {
                                            dump($e->getMessage());
                                            Db::rollback();
                                        }
                                    }
                                } else {
                                    echo '卖单限价低于市场标准价' . $price . '，匹配失败';
                                }
                            }
                        } else {
                            $url = $this->url . "market/trade?symbol=" . strtolower($coin . $mart);
                            $result = api_curl($url);
                            $client = json_decode($result, true);
                            $price = 0;
                            if (!empty($client['status']) && $client['status'] == 'ok') {
                                $price = $client['tick']['data'][0]['price'];
                            }
                            $minprice = (100 - $configs['blurry']) * $price / 100;
                            $maxprice = (100 + $configs['blurry']) * $price / 100;
                            if (!empty($price) && $price > 0 && $lists['commprice'] >= $minprice && $lists['commprice'] <= $maxprice) {
                                $rdslistsid = 'MatchOrder' . $orders['id'];
                                //进行匹配
                                if (!Redis::get($rdslistsid)) {
                                    Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                    $configs = (new Quotes())->where(['coin' => $orders['coin'], 'mart' => $orders['mart']])->field('buyhand,sellhand')->find();
                                    Db::startTrans();
                                    try {
                                        $this->matchOrders($orders, $lists, $orders['commprice'], $configs);
                                        Db::commit();
                                    } catch (\Exception $e) {
                                        dump($e->getMessage());
                                        Db::rollback();
                                    }
                                }
                            } else {
                                echo '卖单限价低于市场标准价' . $price . '，匹配失败';
                            }
                        }
                    }
                } else {
                    if ($orders['prmoney'] == 1) {
                        //计算买单限价对卖单市价的价格
                        $coin = Configs::get('config.coins.' . $lists['coin']);
                        $mart = Configs::get('config.coins.' . $lists['mart']);
                        if ($lists['coin'] == 1) {
                            if ($mart == 'USDT') {
                                $price = (new Orderlog())->where(['coins' => $orders['coin'], 'mart' => $orders['mart']])->order('id desc')->value('price') ?? 0;
                                if ($price == 0) {
                                    $price = (new Price())->where('dates', '<=', date('Y-m-d'))->where(['coin' => $orders['coin'], 'mart' =>  $orders['mart'], 'istrue' => 1])->order('dates desc')->value('price') ?? 0;
                                }
                                $minprice = (100 - $configs['blurry']) * $price / 100;
                                $maxprice = (100 + $configs['blurry']) * $price / 100;
                                if (!empty($price) && $price > 0 && $lists['commprice'] >= $minprice && $lists['commprice'] <= $maxprice) {
                                    $rdslistsid = 'MatchOrder' . $orders['id'];
                                    //进行匹配
                                    if (!Redis::get($rdslistsid)) {
                                        Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                        Db::startTrans();
                                        try {
                                            $this->matchOrders($orders, $lists, $orders['commprice'], $configs);
                                            Db::commit();
                                        } catch (\Exception $e) {
                                            dump($e->getMessage());
                                            Db::rollback();
                                        }
                                    }
                                } else {
                                    echo '买单限价高于市场标准价' . $price . '，匹配失败';
                                }
                            }
                        } else {
                            $url = $this->url . "market/trade?symbol=" . strtolower($coin . $mart);
                            $result = api_curl($url);
                            $client = json_decode($result, true);
                            $price = 0;
                            if (!empty($client['status']) && $client['status'] == 'ok') {
                                $price = $client['tick']['data'][0]['price'];
                            }
                            $minprice = (100 - $configs['blurry']) * $price / 100;
                            $maxprice = (100 + $configs['blurry']) * $price / 100;
                            if (!empty($price) && $price > 0 && $orders['commprice'] >= $minprice && $orders['commprice'] <= $maxprice) {
                                $rdslistsid = 'MatchOrder' . $orders['id'];
                                //进行匹配
                                if (!Redis::get($rdslistsid)) {
                                    Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                    $configs = (new Quotes())->where(['coin' => $orders['coin'], 'mart' => $orders['mart']])->field('buyhand,sellhand')->find();
                                    Db::startTrans();
                                    try {
                                        $this->matchOrders($orders, $lists, $orders['commprice'], $configs);
                                        Db::commit();
                                    } catch (\Exception $e) {
                                        dump($e->getMessage());
                                        Db::rollback();
                                    }
                                }
                            } else {
                                echo '买单限价高于市场标准价' . $price . '，匹配失败';
                            }
                        }
                    } else {
                        //计算买单限价对卖单市价的价格
                        $coin = Configs::get('config.coins.' . $lists['coin']);
                        $mart = Configs::get('config.coins.' . $lists['mart']);
                        if ($lists['coin'] == 1) {
                            if ($mart == 'USDT') {
                                $price = (new Orderlog())->where(['coins' => $orders['coin'], 'mart' => $orders['mart']])->order('id desc')->value('price') ?? 0;
                                if ($price == 0) {
                                    $price = (new Price())->where('dates', '<=', date('Y-m-d'))->where(['coin' => $orders['coin'], 'mart' =>  $orders['mart'], 'istrue' => 1])->order('dates desc')->value('price') ?? 0;
                                }
                                if (!empty($price) && $price > 0) {
                                    $rdslistsid = 'MatchOrder' . $orders['id'];
                                    //进行匹配
                                    if (!Redis::get($rdslistsid)) {
                                        Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                        $configs = (new Quotes())->where(['coin' => $orders['coin'], 'mart' => $orders['mart']])->field('buyhand,sellhand')->find();
                                        Db::startTrans();
                                        try {
                                            $this->matchOrders($orders, $lists, $price, $configs);
                                            Db::commit();
                                        } catch (\Exception $e) {
                                            dump($e->getMessage());
                                            Db::rollback();
                                        }
                                    }
                                }
                            }
                        } else {
                            $url = $this->url . "market/trade?symbol=" . strtolower($coin . $mart);
                            $result = api_curl($url);
                            $client = json_decode($result, true);
                            $price = 0;
                            if (!empty($client['status']) && $client['status'] == 'ok') {
                                $price = $client['tick']['data'][0]['price'] ?? 0;
                            }
                            if (!empty($price) && $price > 0) {
                                $rdslistsid = 'MatchOrder' . $orders['id'];
                                //进行匹配
                                if (!Redis::get($rdslistsid)) {
                                    Redis::setex($rdslistsid, $rdstime, $orders['id']);
                                    $configs = (new Quotes())->where(['coin' => $orders['coin'], 'mart' => $orders['mart']])->field('buyhand,sellhand')->find();
                                    Db::startTrans();
                                    try {
                                        $this->matchOrders($orders, $lists, $price, $configs);
                                        Db::commit();
                                    } catch (\Exception $e) {
                                        dump($e->getMessage());
                                        Db::rollback();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    //买单  买单  匹配价格
    protected function matchOrders($buyorder = [], $sellorder = [], $price = 0, $configs = [])
    {
        if (empty($buyorder) || empty($sellorder) || $price <= 0 || empty($configs)) {
            return false;
        }
        //判断买单用户剩余可以购买的数量
        $buycannum = floor(($buyorder['commtotal'] - $buyorder['transtotal']) * 10000 / $price) / 10000;
        //判断卖单用户剩余可卖的数量
        $sellcannum = $sellorder['commnum'] - $sellorder['transnum'];
        //判断匹配的币数量
        if ($buycannum > $sellcannum) {
            $cannum = $sellcannum;
        } else {
            $cannum = $buycannum;
        }
        if ($cannum > 0.001) {
            //计算买方均价
            $buytransprice = floor(($buyorder['transtotal'] + $cannum * $price) * 10000  / ($buyorder['transnum'] + $cannum)) / 10000;
            //计算卖方均价
            $selltransprice = floor(($sellorder['transtotal'] + $cannum * $price) * 10000  / ($sellorder['transnum'] + $cannum)) / 10000;
            //手续费计算
            $buyhandfee = floor($cannum * $configs['buyhand'] * 10000 / 100) / 10000; //买入手续费 按币种的计算
            $sellhandfee = floor($cannum * $price * $configs['sellhand'] * 10000 / 100) / 10000; //卖出手续费 按交易市场的计算
            //买单更新
            (new Order())->where('id', $buyorder['id'])->Inc(['transtotal' => ($cannum * $price), 'transnum' => $cannum])
                ->update(['transprice' => $buytransprice]);
            //卖单更新
            (new Order())->where('id', $sellorder['id'])->Inc(['transtotal' => ($cannum * $price), 'transnum' => $cannum])
                ->update(['transprice' => $selltransprice]);
            $canprice = floor($cannum * $price * 10000) / 10000;
            //买家和卖家币种和记录添加
            if ($buyorder['user_id'] > 0) {
                $buyuser =  (new Money())->where(['user_id' => $buyorder['user_id'], 'type' => $buyorder['coin']])->find();
                $buyuserfreeze =  (new Money())->where(['user_id' => $buyorder['user_id'], 'type' => $buyorder['mart']])->find();
                (new Money())->where(['user_id' => $buyorder['user_id'], 'type' => $buyorder['mart'], 'fmoney' => $buyuserfreeze['fmoney']])->setDec('fmoney', $canprice);
                (new Money())->MoneyEdit($buyuser, 0, $cannum, 6, '交易购买', 0, 0);
                $buyuser['money'] = $buyuser['money'] + $cannum;
                (new Money())->MoneyEdit($buyuser, 0, -$buyhandfee, 6, '交易手续费', 0, 0);
            }
            if ($sellorder['user_id'] > 0) {
                $selluser =  (new Money())->where(['user_id' => $sellorder['user_id'], 'type' => $sellorder['mart']])->find();
                $selluserfreeze =  (new Money())->where(['user_id' => $sellorder['user_id'], 'type' => $sellorder['coin']])->find();
                (new Money())->where(['user_id' => $sellorder['user_id'], 'type' => $sellorder['coin'], 'fmoney' => $selluserfreeze['fmoney']])->setDec('fmoney', $cannum);
                (new Money())->MoneyEdit($selluser, 0, $canprice, 6, '交易购买', 0, 0);
                $selluser['money'] = $selluser['money'] + $canprice;
                (new Money())->MoneyEdit($selluser, 0, -$sellhandfee, 6, '交易手续费', 0, 0);
            }
            //添加订单拆分记录
            (new Orderlog())->insertAll([
                [
                    'orderid' => $buyorder['id'],
                    'matchid' => $sellorder['id'],
                    'user_id' => $buyorder['user_id'],
                    'matchuser_id' => $sellorder['user_id'],
                    'type' => $buyorder['type'],
                    'price' => $price,
                    'num' => $cannum,
                    'coins' => $buyorder['coin'],
                    'mart' => $buyorder['mart'],
                    'coinfee' => $buyhandfee,
                    'dates' => date('Y-m-d'),
                    'martfee' => $buyhandfee * $price,
                ], [
                    'orderid' => $sellorder['id'],
                    'matchid' => $buyorder['id'],
                    'user_id' => $sellorder['user_id'],
                    'matchuser_id' => $buyorder['user_id'],
                    'type' => $sellorder['type'],
                    'price' => $price,
                    'num' => $canprice,
                    'coins' => $buyorder['coin'],
                    'mart' => $buyorder['mart'],
                    'coinfee' => round($sellhandfee / $price, 6),
                    'dates' => date('Y-m-d'),
                    'martfee' => $sellhandfee,
                ]
            ]);
        }
        $this->MatchStatus($buyorder['id'], $price);
        $this->MatchStatus($sellorder['id'], $price);
        return true;
    }

    //更新订单状态
    protected function MatchStatus($id = 0, $price = 0)
    {
        if ($id == 0 || $price == 0) {
            return false;
        }
        $order = (new Order())->where('id', $id)->find();
        if (empty($order) || $order['status'] != 1) {
            return false;
        }
        //买单
        if ($order['type'] == 1) {
            $user =  (new Money())->where(['user_id' => $order['user_id'], 'type' => $order['mart']])->find();
            $martprice = $order['commtotal'] - $order['transtotal'];
            if ($martprice < 0.001 && $martprice >= 0) {
                (new Order())->where('id', $order['id'])->update(['status' => 2, 'clostime' => date('Y-m-d H:i:s')]);
                //还原冻结的币
                (new Money())->where(['user_id' => $order['user_id'], 'type' => $order['mart'], 'fmoney' => $user['fmoney']])->setDec('fmoney', $martprice);
            }
        } else {
            $user =  (new Money())->where(['user_id' => $order['user_id'], 'type' => $order['coin']])->find();
            $coinnum = $order['commnum'] - $order['transnum'];
            if ($coinnum < 0.001 && $coinnum >= 0) {
                (new Order())->where('id', $order['id'])->update(['status' => 2, 'clostime' => date('Y-m-d H:i:s')]);
                //还原冻结的币
                (new Money())->where(['user_id' => $order['user_id'], 'type' => $order['coin'], 'fmoney' => $user['fmoney']])->setDec('fmoney', $coinnum);
            }
        }
    }
}
